package org.springblade.ocpp.handle;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springblade.common.constant.ChargerConstant;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.modules.charger.pojo.dto.MeterValuesDTO;
import org.springblade.modules.charger.pojo.entity.ChargeOrderBatteryEntity;
import org.springblade.modules.charger.pojo.entity.ChargerEntity;
import org.springblade.modules.charger.pojo.entity.ChargerOrderEntity;
import org.springblade.modules.charger.pojo.vo.Inside.*;
import org.springblade.modules.charger.service.IChargeOrderBatteryService;
import org.springblade.modules.charger.service.IChargerOrderService;
import org.springblade.modules.charger.service.IChargerService;
import org.springblade.ocpp.domain.req.*;
import org.springblade.ocpp.domain.res.*;
import org.springblade.ocpp.send.DelaySend;
import org.springblade.ocpp.util.GlobalVariable;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author lhb
 * @date 2024/9/10 下午4:11
 */
@AllArgsConstructor
@Component
public class ServerCoreEventHandlerImpl implements ServerCoreEventHandler {

	private final IChargerService chargerService;
	private final IChargerOrderService chargerOrderService;
	private final IChargeOrderBatteryService chargeOrderBatteryService;

	@Override
	public AuthorizeConfirmation handleAuthorizeRequest(AuthorizeRequest request) {
		AuthorizeConfirmation authorizeConfirmation = new AuthorizeConfirmation();
		AuthorizeConfirmation.IdTagInfoDTO idTagInfo = new AuthorizeConfirmation.IdTagInfoDTO();
		idTagInfo.setStatus(GlobalVariable.Status.Accepted.value());
		idTagInfo.setExpiryDate(DateUtil.format(LocalDateTime.now().plusDays(1L), DatePattern.UTC_PATTERN));
		authorizeConfirmation.setIdTagInfo(idTagInfo);
		return authorizeConfirmation;
	}

	@Override
	public BootNotificationConfirmation handleBootNotificationRequest(BootNotificationRequest request) {
		BootNotificationConfirmation bootNotificationConfirmation = new BootNotificationConfirmation();
		bootNotificationConfirmation.setCurrentTime(DateUtil.format(LocalDateTime.now(), DatePattern.UTC_PATTERN));
		bootNotificationConfirmation.setInterval(30);
		bootNotificationConfirmation.setStatus(GlobalVariable.Status.Accepted.value());
		return bootNotificationConfirmation;
	}

	@Override
	public DataTransferConfirmation handleDataTransferRequest(DataTransferRequest request) {
		if ("BatteryId".equals(request.getMessageId())) {
			// 保存充电桩、充电枪、电池信息
			JSONObject data = JSONObject.parseObject(Base64.decodeStr(request.getData()));
			Integer connectorId = data.getInteger("connectorId");
			String batterySn = data.getString("batterySn");
			ChargeOrderBatteryEntity chargeOrderBattery = new ChargeOrderBatteryEntity();
			chargeOrderBattery.setChargerSn(request.getSid());
			chargeOrderBattery.setBatterySn(batterySn);
			chargeOrderBattery.setGunNum(connectorId);
			chargeOrderBatteryService.save(chargeOrderBattery);
		}
		return new DataTransferConfirmation(GlobalVariable.Status.Accepted.value());
	}

	@Override
	public HeartbeatConfirmation handleHeartbeatRequest(HeartbeatRequest request) {
		HeartbeatConfirmation heartbeatConfirmation = new HeartbeatConfirmation();
		heartbeatConfirmation.setCurrentTime(DateUtil.format(LocalDateTime.now(), DatePattern.UTC_PATTERN));
		return heartbeatConfirmation;
	}

	@Override
	public MeterValuesConfirmation handleMeterValuesRequest(MeterValuesRequest request) {
		// 没有订单ID, 更新电池SOC信息
		if (null == request.getTransactionId()) {
			ChargeOrderBatteryEntity orderBattery = chargeOrderBatteryService.getOne(Wrappers.<ChargeOrderBatteryEntity>lambdaQuery()
				.eq(ChargeOrderBatteryEntity::getChargerSn, request.getSid())
				.eq(ChargeOrderBatteryEntity::getGunNum, request.getConnectorId())
				.orderByDesc(ChargeOrderBatteryEntity::getCreateTime)
				.last("LIMIT 0,1")
			);
			if (null != orderBattery) {
				orderBattery.setSocContent(JSONObject.toJSONString(request.getMeterValue().get(0)));
				chargeOrderBatteryService.updateById(orderBattery);
			}

//			// 准备发送 RemoteStartTransaction 信息给充电桩准备开始充电
//			RemoteStartTransactionRequest delay = new RemoteStartTransactionRequest(1);
//			delay.setSid(request.getSid());
//			delay.setConnectorId(request.getConnectorId());
//			delay.setIdTag(IdUtil.fastSimpleUUID());
//			RemoteStartTransactionRequest.ChargingProfileDTO chargingProfile = new RemoteStartTransactionRequest.ChargingProfileDTO();
//			chargingProfile.setChargeProfileId(1);
//			chargingProfile.setChargingProfileKind("Relative");
//			chargingProfile.setChargingProfilePurpose("TxProfile");
//			RemoteStartTransactionRequest.ChargingProfileDTO.ChargingScheduleDTO chargingSchedule = new RemoteStartTransactionRequest.ChargingProfileDTO.ChargingScheduleDTO();
//			chargingSchedule.setChargingRateUnit("A");
//			List<RemoteStartTransactionRequest.ChargingProfileDTO.ChargingScheduleDTO.ChargingSchedulePeriodDTO> chargingSchedulePeriod = new ArrayList<>();
//			RemoteStartTransactionRequest.ChargingProfileDTO.ChargingScheduleDTO.ChargingSchedulePeriodDTO chargingSchedulePeriodDTO = new RemoteStartTransactionRequest.ChargingProfileDTO.ChargingScheduleDTO.ChargingSchedulePeriodDTO();
//			chargingSchedulePeriodDTO.setLimit(60);
//			chargingSchedulePeriodDTO.setStartPeriod(0);
//			chargingSchedulePeriod.add(chargingSchedulePeriodDTO);
//			chargingSchedule.setChargingSchedulePeriod(chargingSchedulePeriod);
//			chargingProfile.setChargingSchedule(chargingSchedule);
//			delay.setChargingProfile(chargingProfile);
//			// 设置到延时队列, 延迟后发送消息到充电桩
//			DelaySend.put(delay);
//
//			// 发送充电站资料给客户端
//			DataTransferRequest dataTransferRequest = new DataTransferRequest(2);
//			dataTransferRequest.setSid(request.getSid());
//			dataTransferRequest.setVendorId("Spiro");
//			dataTransferRequest.setMessageId("ChargingProfile");
//			JSONObject data = new JSONObject();
//			data.put("chargingProfileId", 1);
//			data.put("connectorId", request.getConnectorId());
//			data.put("TargetSOC", 100);
//			data.put("format", "Raw");
//			data.put("unit", "percent");
//			dataTransferRequest.setData(Base64.encode(data.toString()));
//			// 设置到延时队列, 延迟后发送消息到充电桩
//			DelaySend.put(dataTransferRequest);
		} else {
			// 更新设备表中充电枪的功率、电压、电流信息
			ChargerEntity charger = chargerService.getOne(Wrappers.<ChargerEntity>lambdaQuery()
				.eq(ChargerEntity::getChargerSn, request.getSid())
			);
			if (null == charger) {
				throw new ServiceException("Device not registered");
			}

			CurrentJsonVO currentJsonVO = JSONObject.parseObject(charger.getCurrent(), CurrentJsonVO.class);
			VoltageJsonVO voltageJsonVO = JSONObject.parseObject(charger.getCurrent(), VoltageJsonVO.class);
			PowerJsonVO powerJsonVO = JSONObject.parseObject(charger.getCurrent(), PowerJsonVO.class);

			MeterValuesRequest.MeterValueDTO meterValueDTO = request.getMeterValue().get(0);
			// 解析电流
			List<MeterValuesRequest.MeterValueDTO.SampledValueDTO> currentList = meterValueDTO.getSampledValue().stream().filter(v -> "A".equals(v.getUnit())).toList();
			// 解析功率
			List<MeterValuesRequest.MeterValueDTO.SampledValueDTO> voltageList = meterValueDTO.getSampledValue().stream().filter(v -> "V".equals(v.getUnit())).toList();
			// 解析电压
			List<MeterValuesRequest.MeterValueDTO.SampledValueDTO> powerList = meterValueDTO.getSampledValue().stream().filter(v -> "kW".equals(v.getUnit())).toList();

			if (1 == request.getConnectorId()) {
				currentJsonVO.setGunOne(BeanUtil.copyToList(currentList, MeterValuesDTO.class));
				voltageJsonVO.setGunOne(BeanUtil.copyToList(voltageList, MeterValuesDTO.class));
				powerJsonVO.setGunOne(BeanUtil.copyToList(powerList, MeterValuesDTO.class));
			} else if (2 == request.getConnectorId()) {
				currentJsonVO.setGunTwo(BeanUtil.copyToList(currentList, MeterValuesDTO.class));
				voltageJsonVO.setGunTwo(BeanUtil.copyToList(voltageList, MeterValuesDTO.class));
				powerJsonVO.setGunTwo(BeanUtil.copyToList(powerList, MeterValuesDTO.class));
			}

			charger.setCurrent(JSONObject.toJSONString(currentJsonVO));
			charger.setVoltage(JSONObject.toJSONString(voltageJsonVO));
			charger.setPower(JSONObject.toJSONString(powerJsonVO));
			chargerService.updateById(charger);
		}
		return new MeterValuesConfirmation();
	}

	@Override
	public StartTransactionConfirmation handleStartTransactionRequest(StartTransactionRequest request) {

		// 生成订单
		ChargerOrderEntity chargerOrder = new ChargerOrderEntity();
		chargerOrder.setChargerSn(request.getSid());
		chargerOrder.setGunNum(request.getConnectorId());
		LocalDateTime localDateTime = DateUtil.parseLocalDateTime(request.getTimestamp(), DatePattern.UTC_PATTERN);
		chargerOrder.setStartTime(localDateTime);
		chargerOrder.setStartup(ChargerConstant.ChargerOrderStatus.DEVICE_STATUS.getVal());
		chargerOrder.setIdTag(request.getIdTag());
		chargerOrder.setMeterStart(request.getMeterStart());
		chargerOrder.setStatus(ChargerConstant.ChargerOrderStatus2.UNFINISHED.getVal());
		chargerOrderService.save(chargerOrder);

		// 更新充电桩 枪 对应的订单信息
		ChargerEntity charger = chargerService.getOne(Wrappers.<ChargerEntity>lambdaQuery()
			.eq(ChargerEntity::getChargerSn, request.getSid())
		);

		ChargingOrderJsonVO chargingOrderJsonVO = JSONObject.parseObject(charger.getChargingOrder(), ChargingOrderJsonVO.class);
		if (1 == request.getConnectorId()) {
			chargingOrderJsonVO.setGunOne(String.valueOf(chargerOrder.getId()));
		} else {
			chargingOrderJsonVO.setGunTwo(String.valueOf(chargerOrder.getId()));
		}
		charger.setChargingOrder(JSONObject.toJSONString(chargingOrderJsonVO));
		chargerService.updateById(charger);

		StartTransactionConfirmation startTransactionConfirmation = new StartTransactionConfirmation();
		StartTransactionConfirmation.IdTagInfoDTO idTagInfo = new StartTransactionConfirmation.IdTagInfoDTO();
		idTagInfo.setStatus(GlobalVariable.Status.Accepted.value());
		idTagInfo.setExpiryDate(DateUtil.format(localDateTime.plusDays(1), DatePattern.UTC_PATTERN));
		startTransactionConfirmation.setIdTagInfo(idTagInfo);
		startTransactionConfirmation.setTransactionId(chargerOrder.getId());

		// 测试用, 默认30秒后发送远程关闭
//		RemoteStopTransactionRequest remoteStopTransactionRequest = new RemoteStopTransactionRequest(30);
//		remoteStopTransactionRequest.setTransactionId(chargerOrder.getId());
//		remoteStopTransactionRequest.setSid(charger.getChargerSn());
//		DelaySend.put(remoteStopTransactionRequest);

		return startTransactionConfirmation;
	}

	@Override
	public StatusNotificationConfirmation handleStatusNotificationRequest(StatusNotificationRequest request) {
		// 更新充电桩 枪的状态
		ChargerEntity charger = chargerService.getOne(Wrappers.<ChargerEntity>lambdaQuery()
			.eq(ChargerEntity::getChargerSn, request.getSid())
		);
		if (null == charger) {
			throw new ServiceException("The device is not registered with the central system");
		}
		// 充电枪的状态
		StatusJsonVO statusJsonVO = JSONObject.parseObject(charger.getStatusJson(), StatusJsonVO.class);
		// 充电枪对应的订单
		ChargingOrderJsonVO chargingOrderJsonVO = JSONObject.parseObject(charger.getChargingOrder(), ChargingOrderJsonVO.class);
		CurrentJsonVO currentJsonVO = JSONObject.parseObject(charger.getCurrent(), CurrentJsonVO.class);
		VoltageJsonVO voltageJsonVO = JSONObject.parseObject(charger.getCurrent(), VoltageJsonVO.class);
		PowerJsonVO powerJsonVO = JSONObject.parseObject(charger.getCurrent(), PowerJsonVO.class);

		if (1 == request.getConnectorId()) {
			statusJsonVO.setGunOne(request.getStatus());
			if ("Available".equals(request.getStatus())) {
				chargingOrderJsonVO.setGunOne(null);
				currentJsonVO.setGunOne(new ArrayList<>());
				voltageJsonVO.setGunOne(new ArrayList<>());
				powerJsonVO.setGunOne(new ArrayList<>());
			}
		} else if (2 == request.getConnectorId()) {
			statusJsonVO.setGunTwo(request.getStatus());
			if ("Available".equals(request.getStatus())) {
				chargingOrderJsonVO.setGunTwo(null);
				currentJsonVO.setGunTwo(new ArrayList<>());
				voltageJsonVO.setGunTwo(new ArrayList<>());
				powerJsonVO.setGunTwo(new ArrayList<>());
			}
		}
		charger.setStatusJson(JSONObject.toJSONString(statusJsonVO));
		charger.setCurrent(JSONObject.toJSONString(currentJsonVO));
		charger.setVoltage(JSONObject.toJSONString(voltageJsonVO));
		charger.setPower(JSONObject.toJSONString(powerJsonVO));
		charger.setChargingOrder(JSONObject.toJSONString(chargingOrderJsonVO));

		chargerService.update(Wrappers.<ChargerEntity>lambdaUpdate()
			.eq(ChargerEntity::getId, charger.getId())
			.set(ChargerEntity::getStatusJson, charger.getStatusJson())
			.set(ChargerEntity::getChargingOrder, charger.getChargingOrder())
			.set(ChargerEntity::getCurrent, charger.getCurrent())
			.set(ChargerEntity::getVoltage, charger.getVoltage())
			.set(ChargerEntity::getPower, charger.getPower())
		);
		return new StatusNotificationConfirmation();
	}

	@Override
	public FirmwareStatusNotificationConfirmation handleFirmwareStatusNotification(FirmwareStatusNotificationRequest request) {

		return new FirmwareStatusNotificationConfirmation();
	}

	@Override
	public StopTransactionConfirmation handleStopTransactionRequest(StopTransactionRequest request) {
		// 变更订单状态
		ChargerOrderEntity chargerOrder = chargerOrderService.getById(request.getTransactionId());
		if (null == chargerOrder) {
			throw new ServiceException("transactionId inexistence");
		}
		if (ChargerConstant.ChargerOrderStatus2.ALREADYENDED.getVal() == chargerOrder.getStatus()) {
			throw new ServiceException("transactionId Already ended");
		}
		// 变更设备中充电枪和状态
		chargerOrder.setStatus(ChargerConstant.ChargerOrderStatus2.ALREADYENDED.getVal());
		chargerOrder.setMeterStop(request.getMeterStop());
		if ("Remote".equals(request.getReason())) {
			chargerOrder.setShutdown(ChargerConstant.ChargerOrderStatus.CLOUD_STATUS.getVal());
		} else {
			chargerOrder.setShutdown(ChargerConstant.ChargerOrderStatus.DEVICE_STATUS.getVal());
		}

		chargerOrder.setEndTime(DateUtil.parseLocalDateTime(request.getTimestamp(), DatePattern.UTC_PATTERN));
		chargerOrderService.updateById(chargerOrder);

		StopTransactionConfirmation stopTransactionConfirmation = new StopTransactionConfirmation();
		StartTransactionConfirmation.IdTagInfoDTO idTagInfo = new StartTransactionConfirmation.IdTagInfoDTO();
		idTagInfo.setStatus(GlobalVariable.Status.Accepted.value());
		idTagInfo.setExpiryDate(DateUtil.format(LocalDateTime.now().plusDays(1), DatePattern.UTC_PATTERN));
		stopTransactionConfirmation.setIdTagInfo(idTagInfo);
		stopTransactionConfirmation.setTransactionId(chargerOrder.getId());

		// 发送结算信息给充电桩
		DataTransferRequest dataTransferRequest = new DataTransferRequest(1);
		dataTransferRequest.setSid(request.getSid());
		dataTransferRequest.setVendorId("Spiro");
		dataTransferRequest.setMessageId("Payment");

		JSONObject data = new JSONObject();
		data.put("connectorId", chargerOrder.getGunNum());
		data.put("balance", 9100.00);
		data.put("deduction", 90.00);
		dataTransferRequest.setData(Base64.encode(data.toString()));
		// 设置到延时队列, 延迟后发送消息到充电桩
		DelaySend.put(dataTransferRequest);

		return stopTransactionConfirmation;
	}
}
